package com.hlkj.baojin.service.impl;

import com.google.common.collect.Maps;
import com.hlkj.baojin.constant.BaojinConstant;
import com.hlkj.baojin.dao.ICompanyDao;
import com.hlkj.baojin.dao.IDeviceDao;
import com.hlkj.baojin.dao.IDictDAO;
import com.hlkj.baojin.dao.IRealDataDao;
import com.hlkj.baojin.dao.repository.RealDataRepository;
import com.hlkj.baojin.entity.*;
import com.hlkj.baojin.entity.dto.*;
import com.hlkj.baojin.jwt.JwtUser;
import com.hlkj.baojin.service.*;
import com.hlkj.baojin.utils.bean.JsonResult;
import com.hlkj.baojin.utils.lang.DateUtil;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class IRealDataServiceImpl implements IRealDataService {
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private IDeviceDao deviceDao;
    @Autowired
    private IDictDAO dictDAO;
    @Autowired
    private ICompanyDao companyDao;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private AlarmRecordService alarmRecordService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IRealDataDao realDataDao;
    @Autowired
    private RealDataRepository realDataRepository;
    @Autowired
    private ICompanyAreaService companyAreaService;

    @Override
    public JsonResult findList(RealSearchDTO realSearchDTO) {
        JwtUser currentUser = userService.getCurrentUser();

        //如果是公司账号默认添加条件
        if (currentUser.getType() == 1) {
            realSearchDTO.setCompanyId(currentUser.getDeptId());
        }
        //取数据
        ModelList<RealData> list = realDataRepository.findList(realSearchDTO);
        List<RealData> realDatas = list.getList();
        List<RealDataVO> realDataVOS = new ArrayList<>();
        Company companyById = null;
        DeviceDto deviceById = null;
//        VO装换
        for (RealData realData : realDatas) {
            deviceById = deviceService.findDeviceById(realData.getDeviceId());
            companyById = companyDao.findByIdAndDelete(realData.getDeptId(), BaojinConstant.IS_NO_DELETE);
            //如果设备异常不显示实时数据
            if (realData.getStatus().equals(1)) {
                realData.filterReal();
            }
            RealDataVO realDataVO = new RealDataVO(
                    deviceById.getId(),
                    companyById.getName(),
                    companyAreaService.getCompanyAreaNameByCompanyAreaId(deviceById.getCompanyArea()),
                    deviceById.getMonitorObject(),
                    deviceById.getMonitorArticle(),
                    deviceById.getMonitorType(),
                    realData.getReal(),
                    realData.getRealUnit(),
                    realData.getStatus(),
                    realData.isRealStatus()
            );
            realDataVOS.add(realDataVO);
        }

        Map maps = Maps.newHashMap();
        maps.put("list", realDataVOS);
        maps.put("count", list.getCount());
        return JsonResult.success(maps);
    }


    @Override
    public void updateSocketData(List<SoketData> soketDatas) {
        soketDatas.forEach(soketData -> {
            realDataRepository.addDict(1, soketData.getCompanyId(), null);
            Company company = companyDao.findByIndexNumAndDelete(soketData.getCompanyId(),0);
            if (company == null) {
                return;
            }
            soketData.getDataS().forEach(data -> {
                Double aDouble = BaojinConstant.CONVERT_TYPE.get(data.getDataId());
                if(aDouble!=null){
                    //黑名单中的数据按照上限转换百分比
                    data.setValue(Double.valueOf(String.format("%.2f", ((double)data.getValue()*100)/aDouble)));
                }
                if(data.getValue()==null){
                    return;
                }
//                CONVERT_TYPE
                //添加下拉设备编号
                realDataRepository.addDict(2, data.getDataId(), company.getId());
                Device device = deviceDao.findByIndexNumAndBelongCompanyAndDelete(data.getDataId(), company.getId(), BaojinConstant.IS_NO_DELETE);
                if (device != null) {
                    String msg = null;
                    String unit;
                    Double safeValueDown = device.getSafeValueDown();
                    Double safeValueUp = device.getGetSafeValueUp();
                    String down = "无下限";
                    String up = "无上限";
                    if (safeValueDown != null) {
                        down = String.valueOf(safeValueDown.intValue());
                    }
                    if (safeValueUp != null) {
                        up = String.valueOf(safeValueUp.intValue());
                    }
                    // 0.储量 1.温度 2.泄漏量
                    switch (device.getMonitorType()) {
                        case 0:
                            unit = "%";
                            msg = "储量达到" + data.getValue() + "%(" + down + "%-" + up + "%)";
                            break;
                        case 1:
                            unit = "℃";
                            msg = "温度达到" + data.getValue() + "℃(" + down + "℃-" + up + "℃)";
                            break;
                        case 2:
                            unit = "";
                            msg = "泄露量达到" + data.getValue() + "(" + down + "-" + up + ")";
                            break;
                        case 3:
                            unit = "";
                            msg = "液位达到" + data.getValue() + "(" + down + "-" + up + ")";
                            break;
                        default:
                            unit = "";
                            msg = "";
                            break;
                    }
                    //是否报警了
                    boolean isRecover = true;
                    //是否已经上传过报警
                    boolean isSafe = alarmRecordService.findByDevice(device.getId());
                    //是否已经上传过预警
                    boolean isEarly = alarmRecordService.findByDeviceEarly(device.getId());
                    //同意创建时间
                    long createTime = System.currentTimeMillis();
                    //是否需要报警
                    if (device.getSafeValueDown() != null&&device.getSafeValueDown() >= data.getValue()) {
                            if (isSafe) {
                             alarmRecordService.addAlarmRecord(new AlarmRecord(company.getId(), device.getId(), msg,createTime));
                            }
                            isRecover = false;
                    }
                    //是否需要报警
                    if (device.getGetSafeValueUp() != null&&device.getGetSafeValueUp() <= data.getValue()) {
                            if (isSafe) {
                             alarmRecordService.addAlarmRecord(new AlarmRecord(company.getId(), device.getId(), msg,createTime));
                            }
                            isRecover = false;
                    }
                    //预警添加
                    if (device.getEarlyAlarmValueDown() != null&&device.getEarlyAlarmValueDown()  >= data.getValue()) {
                        if (isEarly&&isRecover) {
                            alarmRecordService.addEarlyAlarmRecord(new EarlyAlarmRecord(company.getId(), device.getId(), msg,createTime));
                        }
                        isRecover = false;
                    }
                    if (device.getEarlyAlarmValueUp() != null&&device.getEarlyAlarmValueUp() <= data.getValue()) {
                        if (isEarly&&isRecover) {
                            alarmRecordService.addEarlyAlarmRecord(new EarlyAlarmRecord(company.getId(), device.getId(), msg,createTime));
                        }
                        isRecover = false;
                    }
                    //如果是正常的就恢复这条数据
                    if (isRecover) {
                        //恢复报警时间状态
                        alarmRecordService.recoverAlarm(device.getId(),createTime);
                        //恢复预警时间状态
                        alarmRecordService.recoverEarlyAlarm(device.getId(),createTime);
                    }
                    //恢复设备状态
                    realDataRepository.updateReal(device.getId());
                    deviceService.updateDeviceStatus(device.getId(),0);
                    //保存实时信息日志
                    this.saveStatusDataLog(device.getId(), data.getValue(), isRecover,createTime);
                    realDataDao.save(new RealData(company.getId(), device.getId(), data.getValue(), unit, 0, isRecover,createTime));
                }
            });
        });
    }

    private void saveStatusDataLog(String id, Double value, boolean isRecover, long createTime) {
        long curDayLog = realDataRepository.findCurDayLog(id);
        //如果今天还没创建日志
        if (curDayLog == 0) {
            realDataRepository.saveStatusDataLog(new DeviceStatusDataLog(id, Arrays.asList(new StatusDataLog(value, isRecover,createTime)),createTime));
        }
        if (curDayLog == 1) {
            //如果有就add
            realDataRepository.addStatusDataLog(id, new StatusDataLog(value, isRecover,createTime));
        }
    }

    @Override
    public void updateReal(Long errTime) {
        realDataRepository.updateReal(errTime);
    }

    @Override
    public JsonResult waveMsg(WaveSearchDTO waveSearchDTO) {
        DeviceDto device = deviceService.findDeviceById(waveSearchDTO.getDeviceId());

        Map<String,StatusDataLog> dataList = new TreeMap<>();
        DeviceStatusDataLog deviceStatusDataLog = realDataRepository.waveMsg(waveSearchDTO);
        if (deviceStatusDataLog == null) {
            return JsonResult.success(null);
        }
        deviceStatusDataLog.getDetails().forEach(statusDataLog -> dataList.put(FastDateFormat.getInstance("yyyy/MM/dd HH:mm:ss").format(new Date(statusDataLog.getRealTime())),new StatusDataLog(statusDataLog.getIsRecover(),statusDataLog.getRealValue())));
        //断开连接时候填入空值
        fault(dataList);
        //vo显示
        StatusDataVO statusDataVO = new StatusDataVO(
                dataList.keySet(),
                dataList,
                device.getMonitorType(),
                device.getSafeValueDown(),
                device.getGetSafeValueUp()
        );
        return JsonResult.success(statusDataVO);
    }

    @Override
    public void fault(Map<String, StatusDataLog> dataList) {
        //        故障的两个值
        Map<Date, Fault> fault=new HashMap<>();
        AtomicReference<Date> prev = new AtomicReference<>();
        dataList.keySet().forEach(s -> {
            Date date = new Date(s);
            if(prev.get() !=null){
               //如果两个时间相差大于一分钟
                long minutes = DateUtil.geMinutesOfTwoDate(date, prev.get());
                if(minutes>=1){
                   fault.put(date,new Fault(prev.get(),minutes));
               }
           }
            prev.set(date);
       });
        fault.forEach((next,prevt)->{
            //相差分钟数
            Long minutes = prevt.getM();
            //需要生成数据量（五秒钟一条数据 一分钟生成12）
            Long dataNum=minutes*12;
            Date date=prevt.getDate();
            for (int i = 0; i < dataNum+1; i++) {
                date = new Date(date.getTime() + 5000L);
                dataList.put(FastDateFormat.getInstance("yyyy/MM/dd HH:mm:ss").format(date),new StatusDataLog(null,-10000.00));
            }
        });
    }

    @Override
    public Set<String> getDict(Integer type) {
        Set<String> stringSet = null;
        if (type.equals(1)) {
            stringSet = dictDAO.findByType(type).getKeys();
            List<Company> companyList = companyDao.findByDelete(BaojinConstant.IS_NO_DELETE);
            for (Company company : companyList) {
                stringSet.remove(company.getIndexNum());
            }
        } else if (type.equals(2)) {
            JwtUser currentUser = userService.getCurrentUser();
            //如果是公司账号默认添加条件
            if (currentUser.getType() == 1) {
                stringSet = dictDAO.findByTypeAndCompanyId(type, currentUser.getDeptId()).getKeys();
            } else {
                stringSet = new HashSet<>();
                Set<String> finalStringSet = stringSet;
                dictDAO.findByTypeAndCompanyIdNotNull(type).stream().map(Dict::getKeys).forEach(finalStringSet::addAll);
            }
        }
        List<Device> deviceList = deviceDao.findByDelete(BaojinConstant.IS_NO_DELETE);
        for (Device device : deviceList) {
            if(stringSet != null) {
                stringSet.remove(device.getIndexNum());
            }
        }
        return stringSet.stream().sorted(String::compareTo).collect(Collectors.toCollection(LinkedHashSet::new));
    }
}
